package discovery;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;

import sun.net.util.IPAddressUtil;
import testnode.Test;
import utility.ConfigManager;
import utility.NetworkUtility;

public class DiscoveryNode {

	Logger logger = Logger.getLogger(this.getClass());
	
	private class DiscoveryServerThread extends Thread {
		private DatagramPacket packet;
		
		public DiscoveryServerThread(DatagramPacket packet) {
			this.packet = packet;
		}

		/* (non-Javadoc)
		 * @see java.lang.Thread#run()
		 */
		@Override
		public void run() {
			String data = new String(packet.getData(), 0, packet.getLength());
			
			logger.debug("packet received from: "+packet.getAddress().getHostAddress());
		    logger.debug("nameservice at: "+ data);
		    
		    InetAddress returnAdress = packet.getAddress();
		    
		    try {
				if (returnAdress.equals(NetworkUtility.getLocalIp().getHostAddress())) {
					returnAdress = InetAddress.getByName("127.0.0.1");
				}
			} catch (UnknownHostException e1) {
				e1.printStackTrace();
			}
		    
			String[] dataArray = data.split(":");
			String registryHost = dataArray[0];
			int registryPort = Integer.parseInt(dataArray[1]);

		    if(IPAddressUtil.isIPv4LiteralAddress(registryHost)) {		    	
		    	try {
		    		//create test node
			    	Test testNode = Test.getInstance();
			    	
			    	byte[] reply = testNode.getUniqueId().getBytes();
		    		
		    		int sendPort = config.getInt("coordinatorMulticastPort");
		    				    		
					DatagramPacket pack = new DatagramPacket(reply, reply.length, returnAdress, sendPort);
					
					DatagramSocket socket = new DatagramSocket();
					socket.send(pack);
					
					if (registryHost.equals(NetworkUtility.getLocalIp().getHostAddress())) {
						registryHost = "127.0.0.1";
					}
					
					// test node rmi binding
					testNode.bindToRegistry(registryHost, registryPort);
				} catch (Exception e) {
					logger.debug("Fehler beim Senden des Pakets!", e);
				}
		    }
		}		
	}
	
	private ConfigManager config;
	
	public DiscoveryNode() throws ConfigurationException {
		logger.debug("DiscoveryNode started");
		config = ConfigManager.getInstance();
	}
	
	public void receive() throws IOException {
		
		int receivePort = config.getInt("testnodeMulticastPort");
		
		MulticastSocket socket = new MulticastSocket(receivePort);
		InetAddress group = InetAddress.getByName(config.getString("multicastAddress"));
		socket.joinGroup(group);

		byte[] buf;
		DatagramPacket packet;
		while(true) {
		    buf = new byte[16];
		    packet = new DatagramPacket(buf, buf.length);
		    socket.receive(packet);
		    
		    (new DiscoveryServerThread(packet)).start();		    
		}
	}
	
	public void startDiscovery()
	{
		
	}
	
	/**
	 * Versucht jede RMI Registry aus der übergegebenen Liste zu kontaktieren und den TestNode dort zu registrieren.
	 * @param RegistryList
	 */
	public void tryRegistrationAtNameservice(ArrayList<String> RegistryList)
	{
		for(String registryAddress : RegistryList)
		{
			try
			{
				Test.getInstance().bindToRegistry(registryAddress);
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {		
		try {
			DiscoveryNode server = new DiscoveryNode();
						
			server.receive();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
